#include "netComponents.h"
#include <QtDebug>

#define NODEPROC_RECVSPACE    (2048)    // 数据接收预留空间大小

nodeProc::nodeProc(NodeProcCallback *pCallBack)
        : m_pDataCallBack(pCallBack)
		, m_nProc(INVALID_SOCKET)
		, m_nHeart(INVALID_SOCKET)
		, m_pRecvData(nullptr)
		, m_bExit(false)
{
	m_strNodeProcID.clear();
    m_listSendMsg.clear();
}

nodeProc::~nodeProc()
{
	release();
}

// 释放资源
void nodeProc::release()
{
	m_bExit = true;

    {
        std::unique_lock<std::mutex> lck (m_mtxSendMsg);
        m_condSendMsg.notify_all();
    }

	if(m_threadHeartBeat.joinable())
	{
		m_threadHeartBeat.join();
	}

	if(m_threadSendMsg.joinable())
	{
		m_threadSendMsg.join();
	}

	if(nullptr != m_pRecvData)
	{
		free(m_pRecvData);
		m_pRecvData = nullptr;
	}
}

// 初始化心跳和数据发送套接字
bool nodeProc::initSocket(CONNECT_TYPE nType, SOCKET nProc)
{
	bool bRet = false;

    do
    {
        if( CONNECT_TYPE_UNKNOW == nType || INVALID_SOCKET == nProc )
        {
            break;
        }

        switch (nType)
        {
        case CONNECT_TYPE_LOGIN:
          	// 客户端用登录的套接字发送数据，则处理端创建心跳线程获取数据
		  	m_nHeart = nProc;
            break;
        case CONNECT_TYPE_HEART:
           	// 处理端将其他数据转发给客户端，用于发送数据
		   	m_nProc = nProc;
            break;
        default:
            break;
        }

        // 两者均不为无效套接字，则返回配置成功
        if(INVALID_SOCKET != m_nProc && INVALID_SOCKET != m_nHeart)
        {
            bRet = true;
        }

    }while(0);

	return bRet;
}

// 根据已配置套接字内容，创建响应线程处理数据
bool nodeProc::init(const std::string &strNodeProcID)
{
	bool bRet = false;
	do
	{
		if(strNodeProcID.empty())
        {
			qDebug() << "[nodeProc::init] strNodeProcID is null: " << QString::fromStdString(strNodeProcID);
            break;
        }

        // 两者均不为无效套接字，则返回配置成功
        if(INVALID_SOCKET == m_nProc || INVALID_SOCKET == m_nHeart)
        {
			qDebug() << "[nodeProc::init] invalid socket: " << m_nProc << m_nHeart;
            break;
        }

		m_strNodeProcID.assign(strNodeProcID);
        m_pRecvData = (char *)malloc(NODEPROC_RECVSPACE);
        if(nullptr == m_pRecvData)
        {
            qDebug() << "[nodeProc::init] m_pRecvData malloc faild";
            break;
        }

        // 创建相应线程
        try
        {
			memset(m_pRecvData, 0x0, sizeof(char) * NODEPROC_RECVSPACE);
            m_threadHeartBeat = std::thread(&nodeProc::threadHeartBeatAndRecv, this, m_pRecvData);
            m_threadSendMsg = std::thread(&nodeProc::threadSendMsg, this);
        }
        catch (...)
        {
            qDebug() << "[nodeProc::init] create threads or memset faild";
            break;
        }

		qDebug() << "[nodeProc::init] node init done! " << QString::fromStdString(strNodeProcID);

		bRet = true;
	} while (0);
	
	return bRet;	
}

// 插入待发送数据，异步发送
void nodeProc::insertMsg(const std::string &strMsg)
{
	if(strMsg.empty())
    {
        return;
    }

    std::unique_lock<std::mutex> lck (m_mtxSendMsg);
    m_listSendMsg.push_back(strMsg);
    m_condSendMsg.notify_all();
}

// 心跳线程
void nodeProc::threadHeartBeatAndRecv(char *pRecvData)
{
	if(nullptr == pRecvData)
	{
		qDebug() << "[nodeProc::threadHeartBeatAndRecv] pRecvData is null: " << pRecvData;
		return;
	}

    if( INVALID_SOCKET == m_nHeart )
    {
        return;
    }

	int iCnt = 0;
    MSG_INFO_TYPE nType = MSG_INFO_TYPE_MSGDATA;
	while (!m_bExit)
	{
		memset(pRecvData, 0x0, sizeof(char) * NODEPROC_RECVSPACE);
        int nRet = MyDataRecv(m_nHeart, pRecvData, NODEPROC_RECVSPACE, MAX_DATA_SEND_RECV_TIMEOUT_MS);
        if (0 == nRet)
        {
            iCnt++;
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            if(iCnt >= NODEPROC_TRTTIMES)
            {
                // 接收数据失败超过指定个数，跳出，判定为掉线
			   	qDebug() << "[nodeProc::threadHeartBeatAndRecv] recv data faild curCnt " << iCnt << ", more than " << NODEPROC_TRTTIMES;
                nType = MSG_INFO_TYPE_STATUS_OFF;
                break;
            }
            else
            {
                continue;
            }
        }

		std::string strRecvMsg(pRecvData);
		// 判断是否为心跳应答报文
        if(strRecvMsg == gstrHeartEmptyMsg)
        {
            // 心跳报文不做处理
			//qDebug() << "[nodeProc::threadHeartBeatAndRecv] get heartbeat";
        }
        else if(strRecvMsg == gstrNodeOffline)
        {
            // 节点退出信号，退出并通知上层删除节点
            qDebug() << "[nodeProc::threadHeartBeatAndRecv] ready to offline";
            nType = MSG_INFO_TYPE_STATUS_EXIT;
            break;
        }
		else
		{
            // 非心跳应答报文，则将数据回到给调度类，由调度类转发给UI展示
            if(nullptr != m_pDataCallBack)
            {
                m_pDataCallBack->funcDataCallbackMsg(m_strNodeProcID, strRecvMsg);
            }
		}
	}

    // 非线程主动退出状态的，表明掉线，则上报状态异常
    if(false == m_bExit)
    {
        qDebug() << "[nodeProc::threadHeartBeatAndRecv] Node is Offline, notify to delete it";
        m_pDataCallBack->funcDataCallbackStatus(nType, m_strNodeProcID);
    }

    if( INVALID_SOCKET != m_nHeart )
    {
        closesocket(m_nHeart);
        m_nHeart = INVALID_SOCKET;
    }
}

// 数据发送线程
void nodeProc::threadSendMsg()
{
    if( INVALID_SOCKET == m_nProc )
    {
        return;
    }

    uint iSendErrCount = 0;
    MSG_INFO_TYPE nType = MSG_INFO_TYPE_MSGDATA;
    while (!m_bExit)
    {
        std::list<std::string> listMsg;
        {
            std::unique_lock<std::mutex> lck (m_mtxSendMsg);
            m_condSendMsg.wait_for(lck, std::chrono::seconds(NODEPROC_WAITTIME_S), [&](){return (!m_listSendMsg.empty() || m_bExit);});
            if(!m_listSendMsg.empty())
            {
                listMsg.swap(m_listSendMsg);
            }
        }

        if(m_bExit)
        {
            break;
        }

        bool bSendStatus = true;
        if(listMsg.empty())
        {
            // 报文组为空，则发送心跳报文给客户端
            int iSendLen = gstrHeartEmptyMsg.length();
            int iRetLen = MyDataSend(m_nProc, gstrHeartEmptyMsg.c_str(), iSendLen, MAX_DATA_SEND_RECV_TIMEOUT_MS);
            if(iRetLen != iSendLen)
            {
                //qDebug() << "[nodeProc::threadSendMsg] send msg faild, sendLen: " << iRetLen << " iSendErrCount:" << iSendErrCount;
                bSendStatus = false;
            }
        }
        else
        {
            // 发送所有消息报文
            for(auto it : listMsg)
            {
                int iSendLen = it.length();
                int iRetLen = MyDataSend(m_nProc, it.c_str(), iSendLen, MAX_DATA_SEND_RECV_TIMEOUT_MS);
                if(iRetLen != iSendLen)
                {
                    //qDebug() << "[nodeProc::threadSendMsg] send msg faild, sendLen: " << iRetLen << " iSendErrCount:" << iSendErrCount;
                    bSendStatus = false;
                    break;
                }
            }
        }

        // 发送数据失败，累计个数
        if(false == bSendStatus)
        {
            iSendErrCount++;
        }

        if(iSendErrCount >= NODEPROC_TRTTIMES)
        {
            qDebug() << "[nodeProc::threadSendMsg] send msg faild, iSendErrCount:" << iSendErrCount;
            nType = MSG_INFO_TYPE_STATUS_OFF;
            break;
        }
    }

    // 非线程主动退出状态的，表明掉线，则上报状态异常
    if(false == m_bExit)
    {
        qDebug() << "[nodeProc::threadSendMsg] Node is Offline, notify to delete it";
        m_pDataCallBack->funcDataCallbackStatus(nType, m_strNodeProcID);
    }

    if( INVALID_SOCKET != m_nProc )
    {
        closesocket(m_nProc);
        m_nProc = INVALID_SOCKET;
    }
}